#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <kernel/rdisk.h>

static void *read_file(char *file_name)
{
	FILE *file;
	file = fopen(file_name, "r");
	if(!file) {
		printf("Failed to open file: %s\n", file_name);
		exit(1);
	}
	int error = fseek(file, 0, SEEK_END);
	if(error == -1) {
		printf("Failed to SEEK_END: %s\n", file_name);
		exit(1);
	}
	long len = ftell(file);
	if(len == -1) {
		printf("Failed to ftell: %s\n", file_name);
		exit(1);
	}
	rewind(file);
	void *data = malloc(len);
	size_t result;
	result = fread(data, 1, len, file);
	if(result != len) {
		printf("Failed to read all bytes: %s\n", file_name);
		exit(1);
	}
	fclose(file);
	return data;
}

static long get_file_length(char *file_name)
{
	FILE *file;
	file = fopen(file_name, "r");
	if(!file) {
		printf("Failed to open file: %s\n", file_name);
		exit(1);
	}
	int error = fseek(file, 0, SEEK_END);
	if(error == -1) {
		printf("Failed to SEEK_END: %s\n", file_name);
		exit(1);
	}
	long len = ftell(file);
	fclose(file);
	return len;
}

static void write_file(char *file_name, void *data, long len)
{
	FILE *file;
	file = fopen(file_name, "w");
	if(!file) {
		printf("Failed to open file: %s\n", file_name);
		exit(1);
	}
	size_t result;
	result = fwrite(data, 1, len, file);
	if(result != len) {
		printf("Failed to write all bytes: %s\n", file_name);
		exit(1);
	}
	fclose(file);
}

static char *get_file_name(char *path)
{
	size_t i, len = strlen(path), loc = 0;
	//Find the last slash
	for(i = 0; i < len; i++) {
		if(path[i] == '/')
			loc = i + 1;
	}
	return path + loc;
}


int main(int nr, char *args[])
{
	if(nr < 3) {
		printf("mkrdisk <output_file_name> <input_file_name1> [input_file_name2]...\n");
		exit(1);
	}

	//
	// Get the output file name.
	//

	char *output_file_name = args[1];

	//
	// Compute the total files and descriptor length.
	//

	u64 files_len = 0, descs_len = 0;
	int i;
	for(i = 2; i < nr; i++) {
		descs_len += sizeof(struct rdisk_file_desc);
		files_len += get_file_length(args[i]);
	}

	//
	// Add a blank descriptor to mark the end.
	//

	descs_len += sizeof(struct rdisk_file_desc);

	printf("Making rdisk..\n");
	printf("Descriptors: %llu B\n", descs_len);
	printf("Files: %llu B\n", files_len);
	
	//
	// Allocate and zero out memory for all the files.
	//

	void *buf = malloc(descs_len + files_len);
	memset(buf, 0, descs_len + files_len);
	
	//
	// Point to the first descriptor.
	//

	struct rdisk_file_desc *descs = (struct rdisk_file_desc *)buf;

	//
	// Point to the first file data location.
	//

	u64 file_ptr = descs_len;

	for(i = 2; i < nr; i++) {

		//
		// Get the file name and data.
		//

		char *file_name = get_file_name(args[i]);
		u64 file_length = get_file_length(args[i]);
		void *file_data = read_file(args[i]);

		printf("Adding file %s, length = %llu B\n", file_name, file_length);
		
		
		/*unsigned char *bufout;
		unsigned int outlen;
		huffman_encode_memory(file_data, flen, &bufout, &outlen);
		printf("%llu B encoded to: %llu B\n", flen, outlen);
		free(bufout);*/

		//
		// Fill in the descriptor.
		//

		strcpy(descs[i - 2].file_name, file_name);
		descs[i - 2].length = file_length;
		descs[i - 2].offset = file_ptr;

		//
		// Copy file data to the file data location pointer.
		//

		memcpy(buf + file_ptr, file_data, file_length);

		//
		// Advance the file data location pointer.
		//

		file_ptr += file_length;
	}

	//
	// Write out the entire buffer.
	//
	write_file(output_file_name, buf, descs_len + files_len);

	return 0;
}
